package com.feishi.core.util.ssh;


import com.feishi.core.util.common.bean.CallFunction;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

/**
 * @version 1.0
 * @auth caixq
 * @time 18-6-28 17:27
 **/

public class SSHClient {
    private String host;
    private String userName;
    private String password;
    private Session session;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void connectSession() throws JSchException {
        this.session = createSession(host, userName, password);
        session.connect();

    }

    public void runCmd(String cmd, boolean isWait) throws InterruptedException, JSchException, IOException {
        runCmd(cmd, isWait, null);
    }

    public void runCmd(String cmd, boolean isWait, CallFunction.voidFunction2<String, String> callBack) throws JSchException, IOException, InterruptedException {
        if (session == null) {
            connectSession();
        } else {

            if (!session.isConnected()) {
                try {
                    session.connect();
                } catch (Exception e) {
                    connectSession();
                }
            }
        }

        ChannelExec channel = getChannelExec(session);
        channel.setCommand(cmd);
        channel.setInputStream(null);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        channel.setErrStream(out);
        channel.connect();

        if (isWait) {
            readChannelAndWaitToFinish(channel, cmd, out, callBack);

        } else {
            new Thread(() -> {
                try {
                    readChannelAndWaitToFinish(channel, cmd, out, callBack);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

        }
    }

    private void readChannelAndWaitToFinish(ChannelExec channel, String cmd, ByteArrayOutputStream out, CallFunction.voidFunction2<String, String> callBack) throws IOException, InterruptedException {

        InputStream in = channel.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
        String buf = null;
        StringBuffer buffer = new StringBuffer();

        while (!channel.isClosed()) {
            while (reader.ready()) {
                buf = reader.readLine();
                buffer.append(buf).append("\n");
            }
        }
        channel.disconnect();
        if (callBack != null) {
            try {
                callBack.execute(buffer.toString(), new String(out.toByteArray(), StandardCharsets.UTF_8));
            } catch (Exception e) {
            }
        }
    }

    private ChannelExec getChannelExec(Session session) throws JSchException {
        ChannelExec channel = (ChannelExec) session.openChannel("exec");
        channel.setInputStream(null);
        return channel;
    }

    private Session createSession(String host, String userName, String password) throws JSchException {
        JSch jsch = new JSch();
        Session session = jsch.getSession(userName, host, 22);
        session.setPassword(password);
        session.setTimeout(10000);
        Properties props = new Properties();
        props.put("StrictHostKeyChecking", "no");
        session.setConfig(props);
        return session;
    }


}
